#include <Arduino.h>
#include <U8g2lib.h>
#include <Wire.h>
#include <NTPClient.h>
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <ArduinoJson.h>
#include <ESP8266HTTPClient.h>
#include <ESPAsyncWebServer.h>
#include <FS.h>
#include <Servo.h>
#include "image.cpp"

//---------------------动作定义-------------------
#define ACTION_FRONT 1         // 前进
#define ACTION_BACK 2          // 后退
#define ACTION_LEFT 3          // 左转
#define ACTION_RIGHT 4         // 右转
#define ACTION_UP_LEFT_HAND 5  // 抬起左手
#define ACTION_UP_RIGHT_HAND 6 // 抬起右手
#define ACTION_UP_LEFT_FOOT 7  // 抬起左脚
#define ACTION_UP_RIGHT_FOOT 8 // 抬起右脚
#define ACTION_LIE 9           // 躺下
#define ACTION_SIT_DOWN 10     // 趴下
#define ACTION_REST 11         // 睡觉
#define ACTION_STAND 12        // 站立
//---------------------表情定义-------------------
#define EMOJI_KAI_XIN 0  // 开心
#define EMOJI_SHENG_QI 1 // 生气
#define EMOJI_CUO_WU 2   // 错误
#define EMOJI_HAO_QI 3   // 好奇
#define EMOJI_XI_HUAN 4  // 喜欢
#define EMOJI_NAN_SHOU 5 // 难受
#define EMOJI_YUN 6      // 晕
#define EMOJI_TIAN_QI 7  // 天气
#define EMOJI_SHI_JIAN 8 // 时间
#define EMOJI_LOGO 9     // logo
#define EMOJI_ADC 10     // 电量
#define EMOJI_CLEAR 11   // 清屏
//---------------------按键部分-------------------
#define BUTTON_PIN1 2                    // 按键1引脚（GPIO2）（D4）
#define BUTTON_PIN2 15                   // 按键2引脚（GPIO15）（D15）
volatile bool buttonPressed1 = false;    // 按键1标志
volatile bool buttonPressed2 = false;    // 按键2标志
unsigned long lastPressTime1 = 0;        // 上次按键1时间
unsigned long lastPressTime2 = 0;        // 上次按键2时间
const unsigned long debounceDelay1 = 50; // 按键1消抖时间（ms）
const unsigned long debounceDelay2 = 50; // 按键2消抖时间（ms）
//---------------------ADC部分-------------------
const float voltageDividerRatio = 8.4; // 分压比（8.4倍缩小）
const float minVoltage = 6.4;          // 电源电量为0%时的电压
const float maxVoltage = 8.4;          // 电源电量为100%时的电压
const int numSamples = 10;             // 定义采样次数
float batteryVoltage = 0;              // 计算电池电压
int batteryPercentage = 0;             // 电量百分比
//---------------------舵机部分-------------------
Servo servoLeftHand;      // 声明左手舵机
Servo servoRightHand;     // 声明右手舵机
Servo servoLeftFoot;      // 声明左脚舵机
Servo servoRightFoot;     // 声明右脚舵机
int engineLeftHand = 12;  // 左手舵机引脚
int engineRightHand = 14; // 右手舵机引脚
int engineLeftFoot = 13;  // 左脚舵机引脚
int engineRightFoot = 16; // 右脚舵机引脚
//---------------------屏幕部分-------------------
U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, /* reset=*/U8X8_PIN_NONE, /*clock=*/5, /*data=*/4);
//---------------------网络部分-------------------
const char *apSsid = "EDA-Robot"; // 热点WIFI名称
const char *apPwd = "";           // 热点WIFI密码（无密码）
AsyncWebServer server(80);        // 设置服务器端口
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "ntp1.aliyun.com", 8 * 3600, 60000);
//---------------------天气部分-------------------
const char *weatherApiUrl = "http://api.seniverse.com/v3/weather/daily.json?key="; // 心知天气API地址
String temperature = "";                                                           // 气温
String humidity = "";                                                              // 湿度
String weather = "";                                                               // 天气
String cityName = "";                                                              // 城市
String weatherApiSecret = "";                                                      // 心知天气API密钥
//---------------------状态部分-------------------
bool initWeather = false; // 天气初始化
bool freeState = false;   // 自由模式标签
int prevEmojiState = -1;  // 用于跟踪之前的EmojiState
int actionState = 0;      // 活动状态标签
int emojiState = 0;       // 表情状态标签
//---------------------FS部分-------------------
const char *ssidFile = "/ssid.json"; // 配置存储文件名及路径

// put function declarations here:
void handleRoute();                       // 处理Web站点路由
void loadWiFiConfig();                    // 读取保存在FS文件系统的WIFI信息
void fetchWeather();                      // 获取天气信息
void front();                             // 前进
void back();                              // 后退
void left();                              // 左转
void right();                             // 右转
void sitDown();                           // 坐下
void lie();                               // 趴下
void stand();                             // 站立
void upLeftHand();                        // 抬起左手
void upRightHand();                       // 抬起右手
void upLeftFoot();                        // 抬起左脚
void upRightFoot();                       // 抬起右脚
void rest();                              // 睡觉
void serialListen();                      // 串口监听
void ICACHE_RAM_ATTR handleButtonPress(); // 处理按键中断
float getAverageAdcVoltage();             // 获取电源电压
int mapBatteryPercentage(float voltage);  // 转换电源电压为百分比
void runAction();                         // 执行动作
void changeEmoji();                       // 改变表情

/**
 * 初始化
 */
void setup()
{
  // put your setup code here, to run once:
  u8g2.begin();
  u8g2.setDisplayRotation(U8G2_R2);
  // OLED显示初始化与按键中断配置
  u8g2.firstPage(); // 启动u8g2页面缓冲配置
  do
  {
    // 设置显示字体（14像素高，适合128*64屏幕）
    u8g2.setFont(u8g2_font_ncenB14_tr);
    // 绘制LOGO位图（居中显示）
    // 参数说明：x坐标0（左对齐），Y坐标（64/2-22/2）=21（垂直居中）
    // 位图尺寸：宽度128px,高度22px,数据源为logo数组
    u8g2.drawXBMP(0, (64 / 2 - 22 / 2), 128, 22, logo);
  } while (u8g2.nextPage());

  // 按钮1配置（通常对应GPIO2）
  // 硬件要求：按钮接地触发，内置上拉保持高电平
  pinMode(BUTTON_PIN1, INPUT_PULLUP);
  // 配置下降沿中断（物理按下时产生低电平）
  attachInterrupt(digitalPinToInterrupt(BUTTON_PIN1), handleButtonPress, FALLING);

  // 按钮2配置（通常对应GPIO15）
  // 硬件要求：需外接上拉电阻，按钮接3.3V触发
  pinMode(BUTTON_PIN2, INPUT); // 无需内部上拉
  // 配置上升沿中断（物理按下时产生高电平）
  attachInterrupt(digitalPinToInterrupt(BUTTON_PIN2), handleButtonPress, RISING);
  // 配置舵机PWM,500us=0度，2500us=180度
  servoRightHand.attach(engineRightHand, 500, 2500);
  servoRightFoot.attach(engineRightFoot, 500, 2500);
  servoLeftHand.attach(engineLeftHand, 500, 2500);
  servoLeftFoot.attach(engineLeftFoot, 500, 2500);
  // 舵机旋转到90度
  servoRightHand.write(90);
  servoRightFoot.write(90);
  servoLeftHand.write(90);
  servoLeftFoot.write(90);
  // 初始化串口
  Serial.begin(115200);
  // 启用SPIFFS文件系统
  SPIFFS.begin();
  // 设置WiFi为热点模式
  WiFi.softAP(apSsid, apPwd);
  Serial.println("热点已启动");
  // 访问的IP地址是ESP8266的默认IP：192.168.4.1
  Serial.print("访问地址：");
  Serial.print(WiFi.softAPIP());
  handleRoute();
  // 加载WiFi配置
  loadWiFiConfig();
  if (WiFi.status() != WL_CONNECTED)
  {
    Serial.println("Starting captive portal..."); // 串口输出
  }
  else
  {
    Serial.println("WiFi connected");
    timeClient.begin();  // NTP服务器初始化
    timeClient.update(); // 获取初始时间
  }
  delay(5000);
  u8g2.clearDisplay(); // 清屏
  do
  {
    u8g2.setFont(u8g2_font_ncenB08_tr);
    u8g2.drawXBMP(0, 0, 64, 64, wifi);
    u8g2.drawStr(64, 10, "WIFI_AP");
    u8g2.drawStr(64, 27, "EDA-Robot");
    u8g2.drawStr(64, 43, "192.168.4.1");
    u8g2.drawStr(64, 60, "WIFI CTRL");
  } while (u8g2.nextPage());
  delay(5000);
  u8g2.clearDisplay();
}

/**
 * 循环执行
 */
void loop()
{
  // put your main code here, to run repeatedly:
  if (Serial.available() > 0)
  {
    serialListen();
  }
  // 对ADC数据多次采样并求平均
  float adcVoltage = getAverageAdcVoltage();
  // 将采样的ADC电压转换为实际电池电压
  batteryVoltage = adcVoltage * voltageDividerRatio; // 计算电池电压
  // 根据电池电压计算电量百分比
  batteryPercentage = mapBatteryPercentage(batteryVoltage);
  if (buttonPressed1)
  {
    // 按键1按下时
    buttonPressed1 = false; // 清除按键标识
    front();
  }
  if (buttonPressed2)
  {
    // 按键2按下时
    buttonPressed2 = false; // 清除按键标识
    back();
  }
  if (freeState)
  {
    emojiState = random(0, 7);
  }
  if (emojiState != prevEmojiState)
  {
    u8g2.clearDisplay();
    prevEmojiState = emojiState;
  }
  changeEmoji();
  if (freeState)
  {
    delay(3000);
    actionState = random(0, 10);
  }
  runAction();
}

void runAction()
{
  switch (actionState)
  {
  case 0:
    /* code */
    break;
  case ACTION_FRONT:
    front();
    actionState = 0;
    break;
  case ACTION_LEFT:
    left();
    actionState = 0;
    break;
  case ACTION_RIGHT:
    right();
    actionState = 0;
    break;
  case ACTION_BACK:
    back();
    actionState = 0;
    break;
  case ACTION_UP_LEFT_HAND:
    upLeftHand();
    actionState = 0;
    break;
  case ACTION_UP_RIGHT_HAND:
    upRightHand();
    actionState = 0;
    break;
  case ACTION_UP_LEFT_FOOT:
    upLeftFoot();
    actionState = 0;
    break;
  case ACTION_UP_RIGHT_FOOT:
    upRightFoot();
    actionState = 0;
    break;
  case ACTION_LIE:
    lie();
    actionState = 0;
    break;
  case ACTION_SIT_DOWN:
    sitDown();
    actionState = 0;
    break;
  case ACTION_REST:
    rest();
    actionState = 0;
    break;
  case ACTION_STAND:
    stand();
    actionState = 0;
    break;
  default:
    break;
  }
}

void changeEmoji()
{
  switch (emojiState)
  {
  case EMOJI_KAI_XIN:
    u8g2.setFont(u8g2_font_ncenB08_tr);
    do
    {
      u8g2.drawXBMP(0, 0, 128, 64, hi);
    } while (u8g2.nextPage());
    break;
  case EMOJI_SHENG_QI:
    u8g2.setFont(u8g2_font_ncenB08_tr);
    do
    {
      u8g2.drawXBMP(0, 0, 128, 64, angry);
    } while (u8g2.nextPage());
    break;
  case EMOJI_CUO_WU:
    u8g2.setFont(u8g2_font_ncenB08_tr);
    do
    {
      u8g2.drawXBMP(0, 0, 128, 64, error);
    } while (u8g2.nextPage());
    break;
  case EMOJI_HAO_QI:
    u8g2.setFont(u8g2_font_ncenB08_tr);
    do
    {
      u8g2.drawXBMP(0, 0, 128, 64, dowhat);
    } while (u8g2.nextPage());
    break;
  case EMOJI_XI_HUAN:
    u8g2.setFont(u8g2_font_ncenB08_tr);
    do
    {
      u8g2.drawXBMP(0, 0, 128, 64, love);
    } while (u8g2.nextPage());
    break;
  case EMOJI_NAN_SHOU:
    u8g2.setFont(u8g2_font_ncenB08_tr);
    do
    {
      u8g2.drawXBMP(0, 0, 128, 64, sick);
    } while (u8g2.nextPage());
    break;
  case EMOJI_YUN:
    u8g2.setFont(u8g2_font_ncenB08_tr);
    do
    {
      u8g2.drawXBMP(0, 0, 128, 64, yun);
    } while (u8g2.nextPage());
    break;
  case EMOJI_TIAN_QI:
    if (WiFi.status() != WL_CONNECTED)
    {
      u8g2.setFont(u8g2_font_ncenB08_tr);
      do
      {
        u8g2.drawXBMP(0, 0, 64, 64, wifi);
        u8g2.drawStr(64, 20, "IP:");
        u8g2.drawStr(64, 40, "192.168.4.1");
        u8g2.drawStr(64, 60, "Need NET");
      } while (u8g2.nextPage());
    }
    else
    {
      fetchWeather();
    }
    break;
  case EMOJI_SHI_JIAN:
    if (WiFi.status() != WL_CONNECTED)
    {
      u8g2.setFont(u8g2_font_ncenB08_tr);
      do
      {
        u8g2.drawXBMP(0, 0, 64, 64, wifi);
        u8g2.drawStr(64, 20, "IP:");
        u8g2.drawStr(64, 40, "192.168.4.1");
        u8g2.drawStr(64, 60, "Need NET");
      } while (u8g2.nextPage());
    }
    else
    {
      do
      {
        timeClient.update();
        u8g2.setFont(u8g2_font_ncenB08_tr);
        timeClient.update();
        u8g2.drawXBMP(0, 0, 64, 64, timeimage);
        int currentHour = timeClient.getHours();
        int currentMinute = timeClient.getMinutes();
        String timeToDisplay = String(currentHour) + ":" + String(currentMinute);

        u8g2.drawStr(64, 30, "TIME");
        u8g2.setCursor(64, 50);
        u8g2.print(timeToDisplay);
      } while (u8g2.nextPage());
    }
    break;
  case EMOJI_LOGO:
    do
    {
      u8g2.setFont(u8g2_font_ncenB08_tr);
      u8g2.drawXBMP(0, (64 / 2 - 22 / 2), 128, 22, logo);
    } while (u8g2.nextPage());
    break;
  case EMOJI_ADC:
    u8g2.setFont(u8g2_font_ncenB08_tr);
    do
    {
      u8g2.drawXBMP(0, 0, 64, 64, book);
      u8g2.drawStr(64, 10, "Voltage");
      // 将 float 转换为字符串并显示
      char buf[10];                       // 用于存储转换后的字符数组
      dtostrf(batteryVoltage, 6, 2, buf); // 转换浮动数值为字符串（宽度为 6，小数点后 2 位）
      u8g2.drawStr(64, 27, buf);
      u8g2.drawStr(64, 43, "Energy");
      dtostrf(batteryPercentage, 6, 2, buf); // 转换浮动数值为字符串（宽度为 6，小数点后 2 位）
      u8g2.drawStr(64, 60, buf);
    } while (u8g2.nextPage());
    break;
  case EMOJI_CLEAR:
    u8g2.clearDisplay();
    break;
  default:
    break;
  }
}

//---------------------页面路由-------------------
/**
 * 处理路由
 */
void handleRoute()
{
  //-------------------------------动作切换------------------------
  // 前进
  server.on("/front", HTTP_GET, [](AsyncWebServerRequest *request)
            {
    actionState = ACTION_FRONT;
    //立即响应客户端，避免阻塞（状态码200,返回纯文本提示信息）
    request->send(200,"text/plain","执行前进动作"); });
  // 后退
  server.on("/back", HTTP_GET, [](AsyncWebServerRequest *request)
            {
    actionState = ACTION_BACK;
    //立即响应客户端，避免阻塞（状态码200,返回纯文本提示信息）
    request->send(200,"text/plain","执行后退动作"); });
  // 左转
  server.on("/left", HTTP_GET, [](AsyncWebServerRequest *request)
            {
    actionState = ACTION_LEFT;
    //立即响应客户端，避免阻塞（状态码200,返回纯文本提示信息）
    request->send(200,"text/plain","执行左转动作"); });
  // 右转
  server.on("/right", HTTP_GET, [](AsyncWebServerRequest *request)
            {
    actionState = ACTION_RIGHT;
    //立即响应客户端，避免阻塞（状态码200,返回纯文本提示信息）
    request->send(200,"text/plain","执行右转动作"); });
  // 抬起左手
  server.on("/uplefthand", HTTP_GET, [](AsyncWebServerRequest *request)
            {
    actionState = ACTION_UP_LEFT_HAND;
    //立即响应客户端，避免阻塞（状态码200,返回纯文本提示信息）
    request->send(200,"text/plain","执行抬起左手动作"); });
  // 抬起右手
  server.on("/uprighthand", HTTP_GET, [](AsyncWebServerRequest *request)
            {
    actionState = ACTION_UP_RIGHT_HAND;
    //立即响应客户端，避免阻塞（状态码200,返回纯文本提示信息）
    request->send(200,"text/plain","执行抬起右手动作"); });
  // 抬起左脚
  server.on("/upleftfoot", HTTP_GET, [](AsyncWebServerRequest *request)
            {
    actionState = ACTION_UP_LEFT_FOOT;
    //立即响应客户端，避免阻塞（状态码200,返回纯文本提示信息）
    request->send(200,"text/plain","执行抬起左脚动作"); });
  // 抬起右脚
  server.on("/uprightfoot", HTTP_GET, [](AsyncWebServerRequest *request)
            {
    actionState = ACTION_UP_RIGHT_FOOT;
    //立即响应客户端，避免阻塞（状态码200,返回纯文本提示信息）
    request->send(200,"text/plain","执行抬起右脚动作"); });
  // 坐下
  server.on("/sitdown", HTTP_GET, [](AsyncWebServerRequest *request)
            {
    actionState = ACTION_SIT_DOWN;
    //立即响应客户端，避免阻塞（状态码200,返回纯文本提示信息）
    request->send(200,"text/plain","执行坐下动作"); });
  // 趴下
  server.on("/lie", HTTP_GET, [](AsyncWebServerRequest *request)
            {
    actionState = ACTION_LIE;
    //立即响应客户端，避免阻塞（状态码200,返回纯文本提示信息）
    request->send(200,"text/plain","执行趴下动作"); });
  // 睡觉
  server.on("/rest", HTTP_GET, [](AsyncWebServerRequest *request)
            {
    actionState = ACTION_REST;
    //立即响应客户端，避免阻塞（状态码200,返回纯文本提示信息）
    request->send(200,"text/plain","执行休息动作"); });
  // 站立
  server.on("/stand", HTTP_GET, [](AsyncWebServerRequest *request)
            {
    actionState = ACTION_STAND;
    //立即响应客户端，避免阻塞（状态码200,返回纯文本提示信息）
    request->send(200,"text/plain","执行站立动作"); });
  // 开启自由模式
  server.on("/free", HTTP_GET, [](AsyncWebServerRequest *request)
            {
    freeState = true;//开启自由模式
    //立即响应客户端，避免阻塞（状态码200,返回纯文本提示信息）
    request->send(200,"text/plain","随机模式已开启"); });
  // 关闭自由模式
  server.on("/offfree", HTTP_GET, [](AsyncWebServerRequest *request)
            {
    freeState = false;//关闭自由模式
    //立即响应客户端，避免阻塞（状态码200,返回纯文本提示信息）
    request->send(200,"text/plain","随机模式已关闭"); });

  //-------------------------------表情切换------------------------
  // 开心
  server.on("/kaixin", HTTP_GET, [](AsyncWebServerRequest *request)
            {
    emojiState = EMOJI_KAI_XIN;
    //立即响应客户端，避免阻塞（状态码200,返回纯文本提示信息）
    request->send(200,"text/plain","切换为开心表情"); });
  // 生气
  server.on("/shengqi", HTTP_GET, [](AsyncWebServerRequest *request)
            {
    emojiState = EMOJI_SHENG_QI;
    //立即响应客户端，避免阻塞（状态码200,返回纯文本提示信息）
    request->send(200,"text/plain","切换为生气表情"); });
  // 错误
  server.on("/cuowu", HTTP_GET, [](AsyncWebServerRequest *request)
            {
    emojiState = EMOJI_CUO_WU;
    //立即响应客户端，避免阻塞（状态码200,返回纯文本提示信息）
    request->send(200,"text/plain","切换为错误表情"); });
  // 好奇
  server.on("/haoqi", HTTP_GET, [](AsyncWebServerRequest *request)
            {
    emojiState = EMOJI_HAO_QI;
    //立即响应客户端，避免阻塞（状态码200,返回纯文本提示信息）
    request->send(200,"text/plain","切换为好奇表情"); });
  // 喜欢
  server.on("/xihuan", HTTP_GET, [](AsyncWebServerRequest *request)
            {
    emojiState = EMOJI_XI_HUAN;
    //立即响应客户端，避免阻塞（状态码200,返回纯文本提示信息）
    request->send(200,"text/plain","切换为喜欢表情"); });

  // 生病
  server.on("/nanshou", HTTP_GET, [](AsyncWebServerRequest *request)
            {
    emojiState = EMOJI_NAN_SHOU;
    //立即响应客户端，避免阻塞（状态码200,返回纯文本提示信息）
    request->send(200,"text/plain","切换为难受表情"); });
  // 头晕
  server.on("/yun", HTTP_GET, [](AsyncWebServerRequest *request)
            {
    emojiState = EMOJI_YUN;
    //立即响应客户端，避免阻塞（状态码200,返回纯文本提示信息）
    request->send(200,"text/plain","切换为晕表情"); });
  // logo
  server.on("/logo", HTTP_GET, [](AsyncWebServerRequest *request)
            {
              emojiState = EMOJI_LOGO;
              //立即响应客户端，避免阻塞（状态码200,返回纯文本提示信息）
              request->send(200,"text/plain","切换为logo表情"); });

  //-------------------------------界面切换------------------------
  // 天气
  server.on("/tianqi", HTTP_GET, [](AsyncWebServerRequest *request)
            { 
              emojiState = EMOJI_TIAN_QI;
              request->send(200, "text/plain", "切换为天气界面"); });
  // 时间
  server.on("/shijian", HTTP_GET, [](AsyncWebServerRequest *request)
            { 
              emojiState = EMOJI_SHI_JIAN;
              request->send(200, "text/plain", "切换为时间界面"); });

  //-------------------------------数据服务------------------------
  // 电池电压
  server.on("/batteryVoltage", HTTP_GET, [](AsyncWebServerRequest *request)
            { request->send(200, "text/plain", String(batteryVoltage)); });
  // 电池电量
  server.on("/batteryPercentage", HTTP_GET, [](AsyncWebServerRequest *request)
            { request->send(200, "text/plain", String(batteryPercentage)); });
  // 连接WIFI
  server.on("/connect", HTTP_POST, [](AsyncWebServerRequest *request)
            { 
              Serial.println("/connect runing");
              //获取POST参数：ssid、pass、city、api
              String ssid = request->getParam("ssid",true)->value();
              String pass = request->getParam("pass",true)->value();
              String city = request->getParam("city",true)->value();
              String api = request->getParam("api",true)->value();

              //打印接收到的参数
              Serial.println(ssid);
              Serial.println(pass);
              //保存WiFi信息到json文件
              DynamicJsonDocument doc(1024);
              doc["ssid"]=ssid;
              doc["pass"]=pass;
              doc["city"]=city;
              doc["api"]=api;
              fs::File file=SPIFFS.open(ssidFile,"w");
              if(file){
                serializeJson(doc,file);//将JSON内容写入文件
                file.close();
              }
              //更新全局变量
              cityName = city;
              weatherApiSecret = api;
              //开始连接WIFI
              WiFi.begin(ssid.c_str(),pass.c_str());
              //发送HTML响应，告知用户正在连接
              //发送UTF-8编码声明的HTML响应
              request->send(200, "text/html;charset=UTF-8", 
              "<!DOCTYPE html>"
              "<html>"
              "<head>"
              "<meta charset='UTF-8'>"
              "<title>状态</title>"
              "</head>"
              "<body>"
              "<h1>请返回使用在线功能，如果能正常获取则配置成功！</h1>"
              "</body>"
              "</html>"
            ); });

  //-------------------------------页面服务------------------------
  // 连接WIFI
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request)
            {
              //检查SPIFFS文件系统中是否存在index.html文件
              if (SPIFFS.exists("/index.html")){
                fs::File file=SPIFFS.open("/index.html","r");
                if(file){
                  size_t fileSize = file.size();
                  String fileContent;
                  while(file.available()){
                    fileContent += (char)file.read();
                  }
                  file.close();
                  request->send(200,"text/html",fileContent);
                  return;
                }
              }
              request->send(404,"text/plain","File Not Found"); });
  // // 控制页面
  // server.on("/control.html", HTTP_GET, [](AsyncWebServerRequest *request)
  //           {
  //             //检查SPIFFS文件系统中是否存在control.html文件
  //             if (SPIFFS.exists("/control.html")){
  //               fs::File file=SPIFFS.open("/control.html","r");
  //               if(file){
  //                 size_t fileSize = file.size();
  //                 String fileContent;
  //                 while(file.available()){
  //                   fileContent += (char)file.read();
  //                 }
  //                 file.close();
  //                 request->send(200,"text/html",fileContent);
  //                 return;
  //               }
  //             }
  //             request->send(404,"text/plain","File Not Found"); });
  // // 配置页面
  // server.on("/setting.html", HTTP_GET, [](AsyncWebServerRequest *request)
  //           {
  //             //检查SPIFFS文件系统中是否存在setting.html文件
  //             if (SPIFFS.exists("/setting.html")){
  //               fs::File file=SPIFFS.open("/setting.html","r");
  //               if(file){
  //                 size_t fileSize = file.size();
  //                 String fileContent;
  //                 while(file.available()){
  //                   fileContent += (char)file.read();
  //                 }
  //                 file.close();
  //                 request->send(200,"text/html",fileContent);
  //                 return;
  //               }
  //             }
  //             request->send(404,"text/plain","File Not Found"); });
  server.serveStatic("/", SPIFFS, "/");
  server.begin();
}

/**
 * 加载WiFi配置
 */
void loadWiFiConfig()
{
  // 初始化SPIFFS文件系统（存储WiFi配置等信息）
  if (SPIFFS.begin())
  {
    // 成功挂载文件系统
    // 尝试打开存储WiFi配置的json文件（需提前创建）
    fs::File file = SPIFFS.open(ssidFile, "r");
    if (file)
    {
      DynamicJsonDocument doc(1024);
      DeserializationError error = deserializeJson(doc, file);
      if (!error)
      {
        // json解析成功
        String ssid = doc["ssid"]; // WiFi名
        String pass = doc["pass"]; // WiFi密码
        String city = doc["city"]; // 城市代码
        String api = doc["api"];   // 天气API密钥
        // 将配置信息赋给全局变量
        cityName = city;
        weatherApiSecret = api;
        // 使用存储的凭证尝试连接WiFi
        WiFi.begin(ssid.c_str(), pass.c_str());
        // 设置5秒钟连接超时
        unsigned long startAttemptTime = millis();
        while (WiFi.status() != WL_CONNECTED && millis() - startAttemptTime < 5000)
        {
          delay(500);
        }
        // 连接状态检测
        if (WiFi.status() != WL_CONNECTED)
        {
          Serial.println("WiFi connection failed,starting captive portal...");
        }
        else
        {
          Serial.println("WiFi connected");
          timeClient.begin(); // 初始化时间客户端
        }
      }
      file.close();
    }
  }
}

/**
 * 获取天气
 */
void fetchWeather()
{ // 获取天气
  if (initWeather == false)
  {
    if (WiFi.status() == WL_CONNECTED)
    {
      WiFiClient client;
      HTTPClient http;
      String apiUrl = weatherApiUrl + weatherApiSecret + "&location=" + cityName + "&language=zh-Hans&unit=c&start=0&days=1";
      if (http.begin(client, apiUrl))
      {
        int httpCode = http.GET();
        if (httpCode > 0)
        {
          String payload = http.getString();
          Serial.println("JSON Response:");
          Serial.println(payload);
          DynamicJsonDocument doc(2048);
          DeserializationError error = deserializeJson(doc, payload);
          if (!error)
          {
            String temperature2 = doc["results"][0]["daily"][0]["high"];  // 最高温度
            String humidity2 = doc["results"][0]["daily"][0]["humidity"]; // 湿度值
            String weather2 = doc["results"][0]["daily"][0]["text_day"];  // 天气描述

            temperature = temperature2;
            humidity = humidity2;
            weather = weather2;
            initWeather = true;

            Serial.print("Data received:");
            Serial.println(temperature);
            Serial.println(humidity);
            Serial.println(weather);
          }
          else
          {
            Serial.println("JSON解析失败：" + String(error.c_str()));
          }
        }
        else
        {
          Serial.printf("HTTP请求失败，错误代码：%d,详情：%s\n", httpCode, http.errorToString(httpCode).c_str());
        }
        http.end();
      }
      else
      {
        Serial.println("服务器连接失败，请检查API地址");
      }
    }
  }

  if (weather == "小雨" || weather == "大雨" || weather == "暴雨" || weather == "雨")
  {
    do
    {
      u8g2.setFont(u8g2_font_ncenB08_tr); // 配置字体
      u8g2.drawXBMP(0, 0, 64, 64, rain);  // 展示图片
      u8g2.drawStr(64, 20, "Temp");       // 显示温度
      String temperatureString = String(temperature) + " C";
      u8g2.drawStr(64, 30, temperatureString.c_str()); // 屏幕显示
      u8g2.drawStr(64, 50, "Humidity");                // 显示湿度
      String humidityString = String(humidity) + " %";
      u8g2.drawStr(64, 60, humidityString.c_str()); // 屏幕显示
    } while (u8g2.nextPage());
  }
  else if (weather == "晴")
  {
    do
    {
      u8g2.setFont(u8g2_font_ncenB08_tr); // 配置字体
      u8g2.drawXBMP(0, 0, 64, 64, sun);   // 展示图片
      u8g2.drawStr(64, 20, "Temp");       // 显示温度
      String temperatureString = String(temperature) + " C";
      u8g2.drawStr(64, 30, temperatureString.c_str()); // 屏幕显示
      u8g2.drawStr(64, 50, "Humidity");                // 显示湿度
      String humidityString = String(humidity) + " %";
      u8g2.drawStr(64, 60, humidityString.c_str()); // 屏幕显示
    } while (u8g2.nextPage());
  }
  else
  {
    do
    {
      u8g2.setFont(u8g2_font_ncenB08_tr); // 配置字体
      u8g2.drawXBMP(0, 0, 64, 64, cloud); // 展示图片
      u8g2.drawStr(64, 20, "Temp");       // 显示温度
      String temperatureString = String(temperature) + " C";
      u8g2.drawStr(64, 30, temperatureString.c_str()); // 屏幕显示
      u8g2.drawStr(64, 50, "Humidity");                // 显示湿度
      String humidityString = String(humidity) + " %";
      u8g2.drawStr(64, 60, humidityString.c_str()); // 屏幕显示
    } while (u8g2.nextPage());
  }
}

// #region 动作代码

/**
 * 前进
 */
void front()
{
  servoRightFoot.write(140);
  servoLeftHand.write(40);
  delay(100);
  servoRightHand.write(40);
  servoLeftFoot.write(140);
  delay(100);

  servoRightFoot.write(90);
  servoLeftHand.write(90);
  delay(100);
  servoRightHand.write(90);
  servoLeftFoot.write(90);
  delay(100);

  servoRightHand.write(140);
  servoLeftFoot.write(40);
  delay(100);
  servoRightFoot.write(40);
  servoLeftHand.write(140);
  delay(100);

  servoRightHand.write(90);
  servoLeftFoot.write(90);
  delay(100);
  servoRightFoot.write(90);
  servoLeftHand.write(90);
  delay(100);
}

/**
 * 后退
 */
void back()
{
  servoLeftHand.write(140);
  servoRightFoot.write(40);
  delay(100);
  servoLeftFoot.write(40);
  servoRightHand.write(140);
  delay(100);

  servoLeftHand.write(90);
  servoRightFoot.write(90);
  delay(100);
  servoLeftFoot.write(90);
  servoRightHand.write(90);
  delay(100);

  servoLeftFoot.write(140);
  servoRightHand.write(40);
  delay(100);
  servoLeftHand.write(40);
  servoRightFoot.write(140);
  delay(100);

  servoLeftFoot.write(90);
  servoRightHand.write(90);
  delay(100);
  servoLeftHand.write(90);
  servoRightFoot.write(90);
  delay(100);
}

/**
 * 左转
 */
void left()
{
  int num = 0;
  while (num < 3)
  {
    servoRightHand.write(80);
    servoLeftFoot.write(80);
    delay(100);
    servoLeftHand.write(120);
    servoRightFoot.write(120);
    delay(100);

    servoRightHand.write(40);
    servoLeftFoot.write(40);
    delay(100);
    servoLeftHand.write(140);
    servoRightFoot.write(140);
    delay(100);

    servoLeftHand.write(90);
    servoRightFoot.write(90);
    servoRightHand.write(90);
    servoLeftFoot.write(90);
    delay(100);

    servoRightHand.write(100);
    servoLeftFoot.write(100);
    delay(100);
    servoLeftHand.write(60);
    servoRightFoot.write(60);
    delay(100);

    servoRightHand.write(90);
    servoLeftFoot.write(90);
    delay(100);
    servoLeftHand.write(40);
    servoRightFoot.write(40);
    delay(100);

    servoLeftHand.write(90);
    servoRightFoot.write(90);
    num++;
  }
}

/**
 * 右转
 */
void right()
{
  int num = 0;
  while (num < 3)
  {
    servoRightHand.write(100);
    servoLeftFoot.write(100);
    delay(100);
    servoLeftHand.write(60);
    servoRightFoot.write(60);
    delay(100);

    servoRightHand.write(140);
    servoLeftFoot.write(140);
    delay(100);
    servoLeftHand.write(40);
    servoRightFoot.write(40);
    delay(100);

    servoLeftHand.write(90);
    servoRightFoot.write(90);
    servoRightHand.write(90);
    servoLeftFoot.write(90);
    delay(100);

    servoRightHand.write(80);
    servoLeftFoot.write(80);
    delay(100);
    servoLeftHand.write(120);
    servoRightFoot.write(120);
    delay(100);

    servoRightHand.write(90);
    servoLeftFoot.write(90);
    delay(100);
    servoLeftHand.write(140);
    servoRightFoot.write(140);
    delay(100);

    servoLeftHand.write(90);
    servoRightFoot.write(90);
    num++;
  }
}

/**
 * 坐下
 */
void sitDown()
{
  servoRightFoot.write(140);
  servoLeftFoot.write(40);
  delay(3000);
  servoRightFoot.write(90);
  servoLeftFoot.write(90);
}

/**
 * 趴下
 */
void lie()
{
  servoRightHand.write(180);
  servoLeftHand.write(0);
  servoRightFoot.write(0);
  servoLeftFoot.write(180);
  delay(3000);

  servoRightHand.write(90);
  servoLeftHand.write(90);
  servoRightFoot.write(90);
  servoLeftFoot.write(90);
}

/**
 * 抬左手
 */
void upLeftHand()
{
  int num = 0;
  while (num < 3)
  {
    servoLeftHand.write(0);
    delay(100);
    servoLeftHand.write(30);
    delay(100);
    num++;
  }
  servoLeftHand.write(90);
}

/**
 * 抬右手
 */
void upRightHand()
{
  int num = 0;
  while (num < 3)
  {
    servoRightHand.write(180);
    delay(100);
    servoRightHand.write(150);
    delay(100);
    num++;
  }
  servoRightHand.write(90);
}

/**
 * 抬左脚
 */
void upLeftFoot()
{
  int num = 0;
  while (num < 3)
  {
    servoLeftFoot.write(0);
    delay(100);
    servoLeftFoot.write(30);
    delay(100);
    num++;
  }
  servoLeftFoot.write(90);
}

/**
 * 抬右脚
 */
void upRightFoot()
{
  int num = 0;
  while (num < 3)
  {
    servoRightFoot.write(180);
    delay(100);
    servoRightFoot.write(150);
    delay(100);
    num++;
  }
  servoRightFoot.write(90);
}

/**
 * 睡觉
 */
void rest()
{
  servoRightHand.write(0);
  servoLeftHand.write(180);
  servoRightFoot.write(180);
  servoLeftFoot.write(0);
}

/**
 * 站立
 */
void stand()
{
  servoLeftHand.write(90);
  servoLeftFoot.write(90);
  servoRightHand.write(90);
  servoRightFoot.write(90);
}

// #endregion

/**
 * 读取电源电压
 */
float getAverageAdcVoltage()
{ // 多次采样求平均值
  long totalAdcValue = 0;
  for (int i = 0; i < numSamples; i++)
  {
    totalAdcValue += analogRead(A0);
    delay(10);
  }
  float averageAdcValue = totalAdcValue / (float)numSamples;
  return (averageAdcValue / 1023.0) * 1.0; // ESP8266的参考电压为1.0V
}

/**
 * 将电压转换为电量百分比
 */
int mapBatteryPercentage(float voltage)
{
  if (voltage <= minVoltage)
    return 0; // 小于等于最小电压时，电量为0%
  if (voltage >= maxVoltage)
    return 100; // 大于等于最大电压时，电量为100%
  // 根据线性比例计算电量百分比
  return (int)((voltage - minVoltage) / (maxVoltage - minVoltage) * 100);
}

/**
 * 按键中断
 */
void ICACHE_RAM_ATTR handleButtonPress()
{
  unsigned long currentTime = millis(); // 获取当前系统运行时间
  if (currentTime - lastPressTime1 > debounceDelay1)
  {
    // 检查按钮1是否满足去抖动条件
    buttonPressed1 = true;
    lastPressTime1 = currentTime;
  }
  unsigned long currentTime2 = millis(); // 获取当前系统运行时间
  if (currentTime2 - lastPressTime2 > debounceDelay1)
  {
    // 检查按钮2是否满足去抖动条件
    buttonPressed2 = true;
    lastPressTime2 = currentTime2;
  }
}

/**
 * 串口监听
 */
void serialListen()
{
  // 读取完整字符串（直到换行符）
  String receiveString = Serial.readStringUntil('\n');
  // 去掉回车符或空格
  receiveString.trim();
  // 处理接收到的字符串
  Serial.print("Received:");
  Serial.println(receiveString);

  if (receiveString == "front")
  { // 前进
    actionState = ACTION_FRONT;
  }
  else if (receiveString == "back")
  { // 后退
    actionState = ACTION_BACK;
  }
  else if (receiveString == "left")
  { // 左转
    actionState = ACTION_LEFT;
  }
  else if (receiveString == "right")
  { // 右转
    actionState = ACTION_RIGHT;
  }
  else if (receiveString == "uplefthand")
  { // 抬起左手
    actionState = ACTION_UP_LEFT_HAND;
  }
  else if (receiveString == "uprighthand")
  { // 抬起右手
    actionState = ACTION_UP_RIGHT_HAND;
  }
  else if (receiveString == "upleftfoot")
  { // 抬起左手
    actionState = ACTION_UP_LEFT_FOOT;
  }
  else if (receiveString == "uprightfoot")
  { // 抬起右手
    actionState = ACTION_UP_RIGHT_FOOT;
  }
  else if (receiveString == "sitdown")
  { // 坐下
    actionState = ACTION_SIT_DOWN;
  }
  else if (receiveString == "lie")
  { // 躺下
    actionState = ACTION_LIE;
  }
  else if (receiveString == "rest")
  { // 睡觉
    actionState = ACTION_REST;
  }
  else if (receiveString == "stand")
  { // 站立
    actionState = ACTION_STAND;
  }
  else if (receiveString == "kaixin")
  { // 开心
    emojiState = EMOJI_KAI_XIN;
  }
  else if (receiveString == "shengqi")
  { // 生气
    emojiState = EMOJI_SHENG_QI;
  }
  else if (receiveString == "cuowu")
  { // 错误
    emojiState = EMOJI_CUO_WU;
  }
  else if (receiveString == "haoqi")
  { // 好奇
    emojiState = EMOJI_HAO_QI;
  }
  else if (receiveString == "xihuan")
  { // 喜欢
    emojiState = EMOJI_XI_HUAN;
  }
  else if (receiveString == "nanshou")
  { // 难受
    emojiState = EMOJI_NAN_SHOU;
  }
  else if (receiveString == "yun")
  { // 晕
    emojiState = EMOJI_YUN;
  }
  else if (receiveString == "tianqi")
  { // 天气
    emojiState = EMOJI_TIAN_QI;
  }
  else if (receiveString == "shijian")
  { // 时间
    emojiState = EMOJI_SHI_JIAN;
  }
  else if (receiveString == "logo")
  { // 嘉立创logo
    emojiState = EMOJI_LOGO;
  }
  else if (receiveString == "adc")
  { // 电源电量
    emojiState = EMOJI_ADC;
  }
  else if (receiveString == "clear")
  { // 清屏
    emojiState = EMOJI_CLEAR;
  }
}